﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core.Utils;

namespace COFE.Core.Entry
{
    public static class IPropertyHostExtension
    {
        #region Property

        /// <summary>
        /// Get all supported properties and actions, if filters != null, the property must also match any or all of the specified filters.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="implementer"></param>
        /// <param name="matchMode"></param>
        /// <param name="filters"></param>
        /// <returns></returns>
        public static object[] GetSupportedProperty<T>(
            this IPropertyHost<T> implementer,
            MatchMode matchMode = MatchMode.All,
            params IPropertyFilter[] filters)
        {
            return implementer.GetSupportedProperty(
                PropertyRetrivalOptions.NotApplied, matchMode, filters);
        }

        /// <summary>
        /// Try to get a property, and use default value if any exception.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="implementer"></param>
        /// <param name="property"></param>
        /// <param name="defaultValue"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static PropertyPair TryGetProperty<T, V>(this IPropertyHost<T> implementer,
            object property, V defaultValue,
            PropertyRetrivalOptions options = PropertyRetrivalOptions.NotApplied)
        {
            try
            {
                return implementer.GetProperty(property, options);
            }
            catch
            {
                return new PropertyPair(property, defaultValue);
            }
        }

        #endregion

        #region PropertyString

        /// <summary>
        /// Is the specific Metadata or resource property supported.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="implementer"></param>
        /// <param name="propertyString"></param>
        /// <returns></returns>
        public static bool IsPropertySupported<T>(this IPropertyHost<T> implementer, 
            string propertyString)
        {
            return implementer.GetSupportedPropertyString<T>()
                .Any((ps) => { return ps.Equals(propertyString, 
                    StringComparison.CurrentCultureIgnoreCase); });
        }

        /// <summary>
        /// Is the specific property is Metadata 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="implementer"></param>
        /// <param name="propertyString"></param>
        /// <returns></returns>
        public static bool HasMetadataPropertyNamed<T>(this IPropertyHost<T> implementer, 
            string propertyString)
        {
            return implementer.GetSupportedPropertyString(true, false)
               .Any((ps) => { return ps.Equals(propertyString, StringComparison.CurrentCultureIgnoreCase); });
        }

        /// <summary>
        /// Is the specific property is Resource
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="implementer"></param>
        /// <param name="propertyString"></param>
        /// <returns></returns>
        public static bool HasResourcePropertyNamed<T>(this IPropertyHost<T> implementer, 
            string propertyString)
        {
            return implementer.GetSupportedPropertyString(false, true)
                .Any((ps) => { return ps.Equals(propertyString, StringComparison.CurrentCultureIgnoreCase); });
        }

        /// <summary>
        /// Get a list of resources marked as Metadata or Resource.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="implementer"></param>
        /// <param name="metadata"></param>
        /// <param name="resource"></param>
        /// <returns></returns>
        public static string[] GetSupportedPropertyString<T>(this IPropertyHost<T> implementer, 
            bool metadata = true, bool resource = true)
        {
            return implementer.GetSupportedProperty()
                .Where((p) =>
                {
                    return (metadata && MetadataExtension.IsMetadata(p)) ||
                        (resource && ResourceExtension.IsResource(p));
                })
                .Select((p) => { return EnumUtils.GetResourceName(p); })
                .ToArray();
        }

        /// <summary>
        /// Get a metadata or resource property.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="implementer"></param>
        /// <param name="propertyString"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static PropertyPair GetProperty<T>(this IPropertyHost<T> implementer,
            string propertyString,
            PropertyRetrivalOptions options = PropertyRetrivalOptions.NotApplied)
        {
            object property = implementer.GetSupportedProperty()
                .Where((p) => { return MetadataExtension.IsMetadata(p) || ResourceExtension.IsResource(p); })
                .Where((p) => { return EnumUtils.GetResourceName(p).Equals(propertyString, StringComparison.CurrentCultureIgnoreCase); })
                .FirstOrDefault();
            if (property != null)
                return implementer.GetProperty(property, options);

            throw new ArgumentException(propertyString);
        }

        /// <summary>
        /// Get a metadata or resource property.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="implementer"></param>
        /// <param name="propertyString"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static void SetProperty<T>(this IPropertyHost<T> implementer,
            string propertyString,
            object value)
        {
            object property = implementer.GetSupportedProperty()
                .Where((p) => { return MetadataExtension.IsMetadata(p) || ResourceExtension.IsResource(p); })
                .Where((p) => { return EnumUtils.GetResourceName(p).Equals(propertyString, StringComparison.CurrentCultureIgnoreCase); })
                .FirstOrDefault();
            if (property != null)
                implementer.SetProperty(property, value);

            throw new ArgumentException(propertyString);
        }

        #endregion

       



    }
}
